using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Text;

using Deepcode.Flux.Core.Services.FileSystem;

namespace Deepcode.Flux.Core.Systems.CMS.TemplateGallery
{
	/// <summary>
	/// Represents the template gallery on the system - implements the singleton 
	/// design pattern.
	/// </summary>
	public class ContentTypes
	{
		#region Singleton design pattern
		/// <summary>
		/// This holds the single(ton) object when it's created
		/// </summary>
		private static ContentTypes _typesObject = null;
		/// <summary>
		/// This static property allows access (and creates if necessary) the content types object
		/// </summary>
		public static ContentTypes Types
		{
			get
			{
				// Create the if necessary
				if( _typesObject == null )
					CreateObject();

				return _typesObject;
			}
		}
		/// <summary>
		/// Foreces the content types singleton to reload next use
		/// </summary>
		public static void ReleaseObject()
		{
			_typesObject = null;
		}
		/// <summary>
		/// The create object method initialises the content types engine
		/// and sets up the appropriate filesystem watchers for if the content
		/// types change
		/// </summary>
		private static void CreateObject()
		{
			try
			{
				_typesObject = new ContentTypes();
				_typesObject.LoadTypes();
			}
			catch( Exception e )
			{
				// If an error occurs during loading, ensure the tree is forced to reload
				ReleaseObject();
				// then rethrow the exception
				throw e;
			}
		}
	
		/// <summary>
		/// Private constructor to prevent creation of this object
		/// </summary>
		private ContentTypes()
		{
		}
		#endregion
		#region Protected / Private Members
		// Holds the collection of content types
		protected List<ContentType> _ContentTypes = new List<ContentType>();
		// Filesystem watcher for template files
		private System.IO.FileSystemWatcher _TemplateWatcher = null;
		#endregion
		#region Initialisation
		/// <summary>
		/// Scans the settings/types directory for *.type.config files and loads them
		/// </summary>
		protected void LoadTypes()
		{
			// Find all of the type files
			FileScanService fss = new FileScanService();
			StringCollection TypeFiles = fss.SearchFilesInWebPath("~/settings/types", "*.type.config", true);
			
			// Load the physical files
			foreach (string TypeFile in TypeFiles)
			{
				ContentType t = new ContentType(TypeFile);
				_ContentTypes.Add( t );
			}
			
			// Link up the objects now everything is loaded
			foreach( ContentType t in _ContentTypes )
				t.BuildRelationships( _ContentTypes );

			// Create filesystem watcher and monitor for changes
			string TemplateDirectory = System.Web.HttpContext.Current.Server.MapPath("~/settings/types/");
			if (System.IO.Directory.Exists(TemplateDirectory))
			{
				_TemplateWatcher = new System.IO.FileSystemWatcher( TemplateDirectory, "*.type.config" );
				_TemplateWatcher.NotifyFilter = 
					System.IO.NotifyFilters.CreationTime |
					System.IO.NotifyFilters.FileName |
					System.IO.NotifyFilters.LastWrite |
					System.IO.NotifyFilters.Size |
					System.IO.NotifyFilters.DirectoryName;

				_TemplateWatcher.IncludeSubdirectories = true;
				_TemplateWatcher.Changed += new System.IO.FileSystemEventHandler(SetFSDirty);
				_TemplateWatcher.Created += new System.IO.FileSystemEventHandler(SetFSDirty);
				_TemplateWatcher.Deleted += new System.IO.FileSystemEventHandler(SetFSDirty);
				_TemplateWatcher.Renamed += new System.IO.RenamedEventHandler(SetFSDirty);
			}
			if( _TemplateWatcher != null ) _TemplateWatcher.EnableRaisingEvents = true;
		}
		/// <summary>
		/// Sets the content type singleton to reload as files have changed
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		void SetFSDirty(object sender, System.IO.FileSystemEventArgs e)
		{
			ContentTypes.ReleaseObject();
		}
		#endregion
		#region Data Retrieval
		/// <summary>
		/// Get all of the content types available on the system
		/// </summary>
		/// <returns></returns>
		public ContentType [] GetAll()
		{
			return _ContentTypes.ToArray();
		}
		/// <summary>
		/// Get the content type by its ID
		/// </summary>
		/// <param name="TypeCode"></param>
		/// <returns></returns>
		public ContentType GetByTypeID(string TypeCode)
		{
			foreach( ContentType t in _ContentTypes )
				if( t.TypeID == TypeCode ) return t;

			return null;
		}
		/// <summary>
		/// Gets all content types that can be added at root
		/// </summary>
		/// <returns></returns>
		public ContentType [] GetAddToRoot()
		{
			List<ContentType> res = new List<ContentType>();
			foreach (ContentType t in _ContentTypes)
				if( t.AddRoot )
					res.Add( t );

			return res.ToArray();
		}
		#endregion
	}
}
